import { SpecService } from './../spec/spec.service';
import { PicClassifyEntity } from 'src/entities/picClassify.entity';
import { PicEntity } from './../entities/pic.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Injectable } from '@nestjs/common';
import {
  GetPicListDto,
  ConfigPicDto,
  DownloadDto,
  GetPicsByTypeDto,
  ProductImgDto,
} from './dto';
import { Repository } from 'typeorm';
import { join } from 'path';
import SpecEntity from 'src/entities/spec.entity';
interface IOverHeight {
  max_width: number;
  max_height: number;
}
const fs = require('fs');
@Injectable()
export class PicsService {
  constructor(
    @InjectRepository(PicEntity)
    private readonly picEntityRepo: Repository<PicEntity>,
    @InjectRepository(PicClassifyEntity)
    private readonly picClassifyRepo: Repository<PicClassifyEntity>,
    private readonly specService: SpecService,
  ) {}
  async getPicList({ keyword = '', classify, page, limit }: GetPicListDto) {
    try {
      const qb = this.picEntityRepo.createQueryBuilder('pic');
      let res: [PicEntity[], number] = [[], 0];
      res =
        !classify || classify.length === 0
          ? await qb
              .where('pic.pic_name LIKE :keyword', { keyword: `%${keyword}%` })
              .orWhere('pic.img_url LIKE :keyword', { keyword: `%${keyword}%` })
              .orWhere('author LIKE :keyword', { keyword: `%${keyword}%` })
              .skip((page - 1) * limit)
              .take(limit)
              .orderBy('pic.create_time')
              .leftJoinAndSelect('pic.classify', 'classify')
              .getManyAndCount()
          : await qb
              .innerJoinAndSelect(
                'pic.classify',
                'classify',
                'classify.id IN (:...classify)',
                { classify },
              )
              .where('pic.pic_name LIKE :keyword', { keyword: `%${keyword}%` })
              .orWhere('pic.img_url LIKE :keyword', { keyword: `%${keyword}%` })
              .orWhere('author LIKE :keyword', { keyword: `%${keyword}%` })
              .leftJoinAndSelect('pic.classify', 'classifys')
              .getManyAndCount();
      return {
        list: res[0],
        total: res[1],
      };
    } catch (e) {
      console.log(e);
      return Promise.reject(e);
    }
  }

  async configPic({
    pic_name,
    img_url,
    classify,
    author,
    max_height,
    max_width,
    id,
    privide_resolution,
    img_info,
  }: ConfigPicDto) {
    try {
      // 分辨率参数为json字符串 转化为json数组对象
      const jsonObj = privide_resolution ? JSON.parse(privide_resolution) : [];
      // 根据分辨率生成对应的所有图片路径
      const promise = await Promise.all<{
        resolution: string;
        img_url: string;
      }>(
        jsonObj.map(item =>
          this.productImg({ img_url, privide_resolution: item }),
        ),
      );
      // 生成缩略图
      const thumb = await this.productThumbnail({ img_url });
      // 生成不同分辨率的图片逻辑
      const resolutionArr = await this.productSpec(promise);
      const images = require('images');
      // 图片过大 相机经常拍出几十m的图片 所以必须进行压缩
      const inputFile = join(__dirname, '..', img_url);
      const compressUrl = `/upload/compress-${img_url
        .split('/upload/')
        .join('')}`;
      const outputFile = join(__dirname, '..', compressUrl);
      images(inputFile).save(outputFile, { quality: 50 });
      // 高大于500的图片进行等比缩放
      const { width, height } = this.overHeight({ max_height, max_width });
      const overHeight = await this.productImg({
        img_url,
        privide_resolution: `${width}*${height}`,
      });
      // 新建修改图片
      const pic = !id ? new PicEntity() : await this.picEntityRepo.findOne(id);
      const qb = this.picClassifyRepo.createQueryBuilder('picClassify');
      const cl = await qb
        .where('picClassify.id IN (:...classify)', { classify })
        .getMany();
      pic.pic_name = pic_name;
      pic.high_img_url = img_url;
      pic.img_url = compressUrl;
      pic.author = author;
      pic.classify = cl;
      pic.max_height = max_height;
      pic.max_width = max_width;
      pic.privide_resolution = privide_resolution;
      pic.img_info = img_info;
      pic.specs = resolutionArr;
      pic.thumb = thumb.img_url;
      pic.list_img_url = overHeight.img_url;
      return await this.picEntityRepo.save(pic);
    } catch (e) {
      console.log('err:', e);
      return Promise.reject(e);
    }
  }
  overHeight({ max_height, max_width }: IOverHeight) {
    const percent = max_width / max_height; // 计算比例
    if (max_height > 500) {
      max_height = 500;
      max_width = max_height * percent;
    }
    return { width: max_width, height: max_height };
  }
  // 生成不同的图片规格
  async productSpec(arr: { resolution: string; img_url: string }[]) {
    const promise = arr.map(item =>
      this.specService.createSpec(item.resolution, item.img_url),
    );
    const res = await Promise.all<SpecEntity>(promise);
    return res;
  }

  // 生成不同分辨率的图片
  async productImg({ img_url, privide_resolution }: ProductImgDto) {
    try {
      // 获取图片
      const path = img_url;
      const type = path.substring(path.indexOf('.'));
      let saveUrl = '';
      // 目前只支持jpg、png两种格式
      if (type === '.jpg') {
        saveUrl = `${
          path.match(/\/upload\/(\S*).jpg/)[1]
        }@${privide_resolution}.jpg`;
      } else if (type === '.png') {
        saveUrl = `${
          path.match(/\/upload\/(\S*).png/)[1]
        }@${privide_resolution}.png`;
      }

      const images = require('images');
      const inputFile = join(__dirname, '..', path.replace(/upload/, 'upload'));

      const outputFile = join(
        __dirname,
        '..',
        `/upload/${saveUrl.replace(/\*/, '_')}`,
      );
      const resolution = privide_resolution.split('*');
      images(inputFile)
        .size(Number(resolution[0]), Number(resolution[1]))
        .save(outputFile, { quality: 50 });
      return {
        resolution: privide_resolution,
        img_url: `/upload/${saveUrl.replace(/\*/, '_')}`,
      };
    } catch (e) {
      return Promise.reject(e);
    }
  }
  // 生成不同的缩略图
  async productThumbnail({
    img_url,
    privide_resolution = '100*100',
  }: ProductImgDto) {
    try {
      // 获取图片
      const path = img_url;
      const type = path.substring(path.indexOf('.'));
      let saveUrl = '';
      // 目前只支持jpg、png两种格式
      if (type === '.jpg') {
        saveUrl = `${
          path.match(/\/upload\/(\S*).jpg/)[1]
        }-thumb@${privide_resolution}.jpg`;
      } else if (type === '.png') {
        saveUrl = `${
          path.match(/\/upload\/(\S*).png/)[1]
        }-thumb@${privide_resolution}.png`;
      }

      const images = require('images');
      const inputFile = join(__dirname, '..', path.replace(/upload/, 'upload'));

      const outputFile = join(
        __dirname,
        '..',
        `/upload/${saveUrl.replace(/\*/, '_')}`,
      );
      const resolution = privide_resolution.split('*');
      images(inputFile)
        .size(Number(resolution[0]), Number(resolution[1]))
        .save(outputFile);
      return {
        resolution: privide_resolution,
        img_url: `/upload/${saveUrl.replace(/\*/, '_')}`,
      };
    } catch (e) {
      return Promise.reject(e);
    }
  }
  async download({ pic_id, privide_resolution }: DownloadDto) {
    try {
      // 获取图片
      const path = (await this.getDetail(pic_id)).img_url;
      const type = path.substring(path.indexOf('.'));
      let saveUrl = '';
      // 目前只支持jpg、png两种格式
      if (type === '.jpg') {
        saveUrl = `${
          path.match(/\/upload\/(\S*).jpg/)[1]
        }@${privide_resolution}.jpg`;
      } else if (type === '.png') {
        saveUrl = `${
          path.match(/\/upload\/(\S*).png/)[1]
        }@${privide_resolution}.png`;
      }

      const images = require('images');
      const inputFile = join(__dirname, '..', path.replace(/upload/, 'upload'));

      const outputFile = join(
        __dirname,
        '..',
        `/upload/${saveUrl.replace(/\*/, '_')}`,
      );
      const resolution = privide_resolution.split('*');
      images(inputFile)
        .size(Number(resolution[0]), Number(resolution[1]))
        .save(outputFile);
      return `/upload/${saveUrl.replace(/\*/, '_')}`;
    } catch (e) {
      return Promise.reject(e);
    }
  }
  async getDetail(id: number) {
    try {
      const pic = await this.picEntityRepo.findOne(id, {
        relations: ['classify'],
      });
      return pic;
    } catch (e) {
      return Promise.reject(e);
    }
  }
  // 删除图片
  async delPic(id: number) {
    try {
      // 先删除原图关联的本地图片
      const one = await this.picEntityRepo.findOne(id, {
        relations: ['specs'],
      });
      const promise = one.specs.map(item =>
        this.deletePicInServerByUrl(item.img_url),
      );
      await Promise.all(promise);
      // 删除本地原图
      await this.deletePicInServerByUrl(one.high_img_url);
      //删除压缩后的本地图片
      await this.deletePicInServerByUrl(one.img_url);
      await this.deletePicInServerByUrl(one.list_img_url);
      // 删除本地缩略图
      const arr = one.high_img_url.split('.');
      await this.deletePicInServerByUrl(`${arr[0]}-thumb@100_100.${arr[1]}`);
      // 删除数据库中的原图以及关联图
      await this.picEntityRepo.delete(id);
    } catch (e) {
      return Promise.reject(e);
    }
  }
  // 根据分类获取相册
  async getPicsByClassify({ id, page, limit }: GetPicsByTypeDto) {
    try {
      const qb = this.picEntityRepo.createQueryBuilder('pics');
      const res = await qb
        .skip(limit * (page - 1))
        .take(limit)
        .innerJoinAndSelect('pics.classify', 'classify', 'classify.id = :id', {
          id,
        })
        .getManyAndCount();
      return {
        list: res[0],
        total: res[1],
      };
    } catch (e) {
      return Promise.reject(e);
    }
  }
  // 通过url删除服务器本地图片
  async deletePicInServerByUrl(img_url: string) {
    const path = join(__dirname, '..', img_url);
    if (fs.existsSync(path)) {
      fs.unlinkSync(path);
    }
  }
}
